package com.feng.test;

/**
 * sleep和wait方法的区别
 * wait方法依赖于同步，而sleep方法可以直接调用。而更深层次的区别在于sleep方法只是暂时让出CPU的执行权，并不释放锁。而wait方法则需要释放锁。
 * 调用wait方法后，线程是会释放对monitor对象的所有权的。
 * 一个通过wait方法阻塞的线程，必须同时满足以下两个条件才能被真正执行：
 * 　　　线程需要被唤醒（超时唤醒或调用notify/notifyll）。
　　　　线程唤醒后需要竞争到锁（monitor）。
 * @author Qian
 *
 */
public class SleepAndWait {
	public synchronized void sleepMethod() {// sleep的同步方法
		System.out.println(Thread.currentThread().getName()+"--Sleep start-----");
		try {
			// 等待1000ms，但是会一直持有对象锁（monitor），并不释放。所以其他线程要等到当前线程结束后才能进入同步方法
			Thread.sleep(1000);//1000ms后线程依然是当前线程继续执行
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(Thread.currentThread().getName()+"--Sleep end-----");
	}

	public synchronized void waitMethod() {// wait的同步方法
		System.out.println(Thread.currentThread().getName()+"--Wait start-----");
		// synchronized (this) {
		try {
			// 等待1000ms，但是会释放对象锁（monitor），所以是三个线程都会进入该同步方法中
			wait(1000);// 超时唤醒。wait方法必须在synchronized中使用.等待1000ms后，线程3,4,5抢到CPU执行权
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		// }
		System.out.println(Thread.currentThread().getName()+"--Wait end-----");
	}

	public static void main(String[] args) {
		final SleepAndWait test1 = new SleepAndWait();

		for (int i = 0; i < 3; i++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					//Thread-0，Thread-1，Thread-2，0线进入，1,2等待0执行完成后抢夺CPU执行权
					test1.sleepMethod();// 调用sleep的同步方法
				}
			}).start();
		}

		try {
			Thread.sleep(8000);// 暂停十秒，等上面程序执行完成
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println("-----分割线-----");

		final SleepAndWait test2 = new SleepAndWait();

		for (int i = 0; i < 3; i++) {
			new Thread(new Runnable() {
				@Override
				public void run() {
					//Thread-3，Thread-4，Thread-5，3进入，3，4，5一起抢夺3调用wait方法后释放的对象锁（monitor）
					test2.waitMethod();// 调用wait的同步方法
				}
			}).start();
		}

	}
	/**
	 * 运行结果：
	 	Thread-0--Sleep start-----线程0先进入
		Thread-0--Sleep end-----线程0 结束，释放对象锁，线程1,2抢夺CPU执行权
		Thread-2--Sleep start-----线程2抢到到CPU执行权
		Thread-2--Sleep end-----
		Thread-1--Sleep start-----
		Thread-1--Sleep end-----
		-----分割线-----
		Thread-3--Wait start-----线程3进去，调用wait方法后释放对象锁，并不用等待，线程4,5就开始抢夺CPU执行权
		Thread-5--Wait start-----线程5抢到，wait后释放
		Thread-4--Wait start-----线程4得到执行权，wait后释放
		Thread-4--Wait end-----等待1000ms（wait（1000）），后线程3,4,5抢夺CPU执行权，线程4抢到
		Thread-3--Wait end-----线程4结束，线程3抢到执行权
		Thread-5--Wait end-----
	 * 通过sleep方法实现的暂停，程序是顺序进入同步块的，只有当上一个线程执行完成的时候，下一个线程才能进入同步方法，
	 * sleep暂停期间一直持有monitor对象锁，其他线程是不能进入的。
	 * 而wait方法则不同，当调用wait方法后，当前线程会释放持有的monitor对象锁，
	 * 因此，其他线程还可以进入到同步方法，线程被唤醒后，需要竞争锁，获取到锁之后再继续执行。
	 */
}
